package models

import (
	"context"
	"database/sql"
	"fmt"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"share/common"
	"strings"
	"time"
)

var _ ShareAggregationModel = (*customerShareAggregationModel)(nil)

type (
	ShareAggregationModel interface {
		shareAggregationModel
	}

	customerShareAggregationModel struct {
		conn               sqlx.SqlConn
		shareModel         defaultShareModel
		shareResourceModel defaultShareResourceModel
		shareTargetModel   defaultShareTargetModel
	}
)

func NewShareAggregationModel(conn sqlx.SqlConn) ShareAggregationModel {
	return &customerShareAggregationModel{
		conn: conn,
	}
}

type (
	shareAggregationModel interface {
		CreateShare(ctx context.Context, share *ShareAggregation) error
		GetShareList(ctx context.Context, userId, status, lastId, limit int64, orderBy string) ([]*ShareAggregation, int64, int64, bool, error)
		GetShareByID(ctx context.Context, shareId int64) (*ShareAggregation, error)
		GetShareByCode(ctx context.Context, shareLink, shareCode string) (*ShareAggregation, error)
	}

	ShareAggregation struct {
		Id         int64        `db:"id"`          // 分享ID（唯一标识）
		UserId     int64        `db:"user_id"`     // 分享者ID（关联users表）
		ShareLink  string       `db:"share_link"`  // 分享链接（如s/abc123,URL路径用）
		ShareCode  string       `db:"share_code"`  // 提取码（share_type=1时必填,share_type=2时为NULL）
		ShareType  int64        `db:"share_type"`  // 分享类型：1-私密分享（需提取码）,2-公开分享（无需提取码）
		Permission int64        `db:"permission"`  // 访问权限：1-仅查看,2-查看+下载,3-查看+下载+保存到我的网盘
		ExpireType int64        `db:"expire_type"` // 过期类型：1-1天,2-7天,3-30天,4-365天,5-永久有效, 6-自定义时间
		ExpireTime sql.NullTime `db:"expire_time"` // 过期时间（expire_type=1时为NULL,其他类型必填）
		Status     int64        `db:"status"`      // 分享状态：1-有效,2-已过期,3-已删除, 4-已取消
		CreateAt   time.Time    `db:"create_at"`   // 创建时间
		UpdateAt   time.Time    `db:"update_at"`   // 更新时间
		FolderIDs  []int64      `db:"folder_ids"`  // 分享的文件夹ID列表（JSON格式）
		FileIDs    []int64      `db:"file_ids"`    // 分享的文件ID列表（JSON格式）
	}
)

func (m *customerShareAggregationModel) CreateShare(ctx context.Context, aggregation *ShareAggregation) error {
	return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
		shareInsertSQL := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", m.shareModel.table, shareRowsExpectAutoSet)
		result, err := session.ExecCtx(ctx, shareInsertSQL, aggregation.UserId, aggregation.ShareLink, aggregation.ShareCode,
			aggregation.ShareType, aggregation.Permission, aggregation.ExpireType, aggregation.ExpireTime, aggregation.Status)
		if err != nil {
			return fmt.Errorf("创建分享失败: %w", err)
		}
		shareId, err := result.LastInsertId()
		if err != nil {
			return fmt.Errorf("获取创建分享标识失败: %w", err)
		}
		// 分享资源构建批量插入SQL
		var placeholders []string
		var args []interface{}
		for _, fileID := range aggregation.FileIDs {
			placeholders = append(placeholders, "(?, ?, ?)")
			args = append(args, shareId, fileID, common.ShareFileType)
		}
		for _, folderID := range aggregation.FolderIDs {
			placeholders = append(placeholders, "(?, ?, ?)")
			args = append(args, shareId, folderID, common.ShareFolderType)
		}

		shareResourceBatchInsertSQL := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", m.shareResourceModel.table, shareResourceRowsExpectAutoSet, strings.Join(placeholders, ","))
		result, err = session.ExecCtx(ctx, shareResourceBatchInsertSQL, args)
		if err != nil {
			return fmt.Errorf("创建分享关联资源失败: %w", err)
		}
		return nil
	})
}

func (m *customerShareAggregationModel) GetShareList(ctx context.Context, userId, status, lastId, limit int64, orderBy string) ([]*ShareAggregation, int64, int64, bool, error) {
	var (
		count        int64
		list         []*ShareAggregation
		placeholders []string
		args         []interface{}
	)
	countQuery := fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE user_id = ? AND status = ?", m.shareModel.table)
	err := m.conn.QueryRowCtx(ctx, &count, countQuery, userId, status)
	if err != nil {
		return nil, 0, 0, false, fmt.Errorf("查询分享总数失败: %w", err)
	}
	listQuery := fmt.Sprintf("SELECT a.*, "+
		"func.array_agg(case when b.resource_type = ? then b.resource_id end) as file_ids, "+
		"func.array_agg(case when b.resource_type = ? then b.resource_id end) as folder_ids "+
		"FROM %s as a join %s as b on a.id = b.share_id "+
		"WHERE a.user_id = ? and a.status = ? GROUP BY a.*",
		m.shareModel.table, m.shareResourceModel.table)
	args = append(args, common.ShareFileType, common.ShareFolderType, userId, status)
	if strings.Contains(orderBy, "desc") {
		placeholders = append(placeholders, "and id < ?")
		args = append(args, lastId)
	} else if strings.Contains(orderBy, "asc") {
		placeholders = append(placeholders, "and id > ?")
		args = append(args, lastId)
	}
	listQuery += fmt.Sprintf(" ORDER BY %s", orderBy)
	listQuery += fmt.Sprintf(" LIMIT %d", limit+1)
	err = m.conn.QueryRowsCtx(ctx, &list, listQuery, args...)
	if err != nil {
		return nil, 0, 0, false, err
	}
	return list[:len(list)-2], count, list[len(list)-1].Id, len(list) > int(limit), nil
}

func (m *customerShareAggregationModel) GetShareByID(ctx context.Context, shareId int64) (*ShareAggregation, error) {
	var share ShareAggregation
	query := fmt.Sprintf("SELECT a.*, "+
		"func.array_agg(case when b.resource_type = ? then b.resource_id end) as file_ids, "+
		"func.array_agg(case when b.resource_type = ? then b.resource_id end) as folder_ids "+
		"FROM %s as a join %s as b on a.id = b.share_id "+
		"WHERE a.id = ? GROUP BY a.*",
		m.shareModel.table, m.shareResourceModel.table)
	err := m.conn.QueryRowCtx(ctx, &share, query, common.ShareFileType, common.ShareFolderType, shareId)
	if err != nil {
		return nil, fmt.Errorf("查询分享失败: %w", err)
	}
	return &share, nil
}

func (m *customerShareAggregationModel) GetShareByCode(ctx context.Context, shareLink, shareCode string) (*ShareAggregation, error) {
	var share ShareAggregation
	query := fmt.Sprintf("SELECT a.*, "+
		"func.array_agg(case when b.resource_type = ? then b.resource_id end) as file_ids, "+
		"func.array_agg(case when b.resource_type = ? then b.resource_id end) as folder_ids "+
		"FROM %s as a join %s as b on a.id = b.share_id "+
		"WHERE a.share_link = ? and a.share_code = ? GROUP BY a.*",
		m.shareModel.table, m.shareResourceModel.table)
	err := m.conn.QueryRowCtx(ctx, &share, query, common.ShareFileType, common.ShareFolderType, shareLink, shareCode)
	if err != nil {
		return nil, fmt.Errorf("查询分享失败: %w", err)
	}
	return &share, nil
}
